package fina2.dcs.mail;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.mail.Authenticator;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.NoSuchProviderException;
import javax.mail.Provider;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.URLName;
import javax.mail.search.SearchTerm;

import org.apache.log4j.Logger;

import fina2.dcs.mail.manager.AttachInfo;
import fina2.dcs.mail.manager.MailPropsKey;
import fina2.dcs.mail.manager.MailUser;
import fina2.dcs.mail.util.MailUtil;

@SuppressWarnings("serial")
public class MailReaderPOP3 implements MailReaderBase {
	private Logger log = Logger.getLogger(getClass());
	private final String folderName = "INBOX";

	private Provider pop3Provider = new Provider(Provider.Type.STORE, "pop3", "com.sun.mail.pop3.POP3Store", "Sun Microsystems, Inc", "1.4.4");
	private Provider pop3SSLProvider = new Provider(Provider.Type.STORE, "pop3", "com.sun.mail.pop3.POP3SSLStore", "Sun Microsystems, Inc", "1.4.4");

	private MailUser mailUser;

	private Session session;
	private Store store;

	private String host;
	private int port;
	private boolean isSSL;

	public MailReaderPOP3(MailUser mailUser) {
		this.mailUser = mailUser;

		initArgs();

		Properties properties = generateProperties();

		URLName urlName = createURLName();

		Authenticator auth = new MailUtil.MyAuthenticator(mailUser.getUser(), mailUser.getPassword());

		session = Session.getInstance(properties, auth);
		// session.setDebug(true);

		try {

			if (isSSL) {
				session.setProvider(pop3SSLProvider);
				store = session.getStore(urlName);
			} else {
				session.setProvider(pop3Provider);
				store = session.getStore(urlName);
			}
		} catch (NoSuchProviderException ex) {
			ex.printStackTrace();
		}
	}

	private URLName createURLName() {
		String protocol = "pop3";
		if (isSSL) {
			protocol = "pop3s";
		}
		return new URLName(protocol, host, port, folderName, mailUser.getUser(), mailUser.getPassword());
	}

	private void initArgs() {
		host = MailUtil.getProperty(MailPropsKey.MAIL_POP3_HOST, mailUser.getProperties());
		port = Integer.parseInt(MailUtil.getProperty(MailPropsKey.MAIL_POP3_PORT, mailUser.getProperties()));
		isSSL = Boolean.parseBoolean(MailUtil.getProperty(MailPropsKey.MAIL_POP3_SSL_ENABLE, mailUser.getProperties()));
	}

	@Override
	public List<AttachInfo> getNewAttahcments(Date date) throws MessagingException {
		List<AttachInfo> mails = new ArrayList<AttachInfo>();

		store.connect();

		Folder folder = openInboxFolder();

		if (folder != null) {
			if (date == null) {
				date = new Date(0);
			}

			final Date finalDate = date;
			Message[] messages = folder.search(new SearchTerm() {
				@Override
				public boolean match(Message msg) {
					boolean result = false;
					try {
						result = (msg.getSentDate().compareTo(finalDate) > 0) && (msg.getSentDate().compareTo(new Date()) < 0);
					} catch (MessagingException e) {
						log.error(e.getMessage(), e);
					}
					return result;
				}
			});

			log.info("New Message Count : " + messages.length);

			for (Message m : messages) {
				AttachInfo info = new AttachInfo();
				info.setReceivedDate(m.getSentDate());
				info.setAddress(m.getFrom());
				try {
					Map<String, byte[]> map = MailUtil.getAttachments(m, mailUser);
					info.setAttachFiles(map);
					log.info(info);
					mails.add(info);
				} catch (Exception ex) {
					log.info("Ignore Message From : " + Arrays.toString(m.getFrom()) + " | Subject : " + m.getSubject() + " | Message(toString) : " + m.toString() + " | Send Date : " + m.getSentDate());
					log.error(ex.getMessage(), ex);
				}
			}
			folder.close(true);
		} else {
			throw new MessagingException("Invalid folder");
		}
		store.close();

		return mails;
	}

	private Folder openInboxFolder() throws MessagingException {
		Folder folder = store.getFolder(createURLName());
		if (folder == null) {
			throw new MessagingException("Invalid folder");
		}
		folder.open(Folder.READ_ONLY);
		return folder;
	}

	@Override
	public boolean equals(Object obj) {
		if (obj instanceof MailReaderPOP3) {
			MailReaderPOP3 m = (MailReaderPOP3) obj;
			return this.mailUser.equals(m.mailUser);
		}
		return false;
	}

	@Override
	public MailUser getMailUser() {
		return this.mailUser;
	}

	private Properties generateProperties() {
		Properties properties = new Properties();
		properties.put(MailPropsKey.MAIL_POP3_HOST, host);
		properties.put(MailPropsKey.MAIL_POP3_PORT, port);
		properties.put(MailPropsKey.MAIL_POP3_CONNECTION_TIMEUT, MailUtil.getProperty(MailPropsKey.MAIL_POP3_CONNECTION_TIMEUT, mailUser.getProperties()));
		properties.put(MailPropsKey.MAIL_POP3_SSL_ENABLE, isSSL);
		return properties;
	}

}
